/**
 * @file   tools.hpp
 * @author wolfhead <wolfhead@wolfhead-laptop>
 * @date   Thu Sep  1 09:55:44 2011
 * 
 * @brief  
 * 
 * 
 */

#ifndef ACAPELLA_TOOLS_HPP
#define ACAPELLA_TOOLS_HPP

namespace acapella
{

/* type select*/
template<bool, typename TrueType, typename FalseType>
struct Select{};

template<typename TrueType, typename FalseType>
struct Select<true, TrueType, FalseType>
{
    typedef TrueType type;
};

template<typename TrueType, typename FalseType>
struct Select<false, TrueType, FalseType>
{
    typedef FalseType type;
};




/**
 * COMPILE_CHECK
 * CompileTimeError check a compile-time constant at compile time
 * USAGE:
 *      COMPILE_CHECK(sizeof(char) > sizeof(int), SIZE_ERROR);
 */
#define COMPILE_CHECK(exp,msg)                                  \
    {                                                           \
        class ERROR_##msg {};                                   \
        (void)sizeof((acapella::__detail__::CompileTimeError    \
                      <(exp) != 0>)                             \
                     (ERROR_##msg()));                          \
    }                                                           \


#define SAMETYPE(TYPE1, TYPE2)                              \
    (acapella::Conversion<const TYPE1, const TYPE2>::same)  \

#define SUPERSUBCLASS(BASE, CHILDREN)                               \
    (acapella::Conversion<const CHILDREN *, const BASE*>::exists && \
     ! acapella::Conversion<const BASE*, const void *>::same)       \

#define SUPERSUBCLASS_STRICT(BASE, CHILDREN)                    \
    (SUPERSUBCLASS(BASE, CHILDREN) &&                           \
     ! acapella::Conversion<const BASE, const CHILDREN>::same)  \


namespace __detail__
{

template<bool>  
struct CompileTimeError
{
    CompileTimeError(...);
};

template<>
struct CompileTimeError<false>
{
};

}//namespace __detail__


/**
 * Int2Type make a dispatch at compile-time 
 * depending on a compile-time constant
 * 
 */
template<int v>
struct Int2Type
{
    enum{value = v};
};


/**
 * Define a unique type for every type given
 * 
 */
template<typename T>
struct Type2Type
{
    typedef T OriginalType;
};


template<typename From, typename To> 
class Conversion
{
private:

    typedef char Convertible;
    class Unconvertible {char dummy[2];};

    static Convertible Test(To);

    static Unconvertible Test(...);

    static From MakeFrom();

public:
    enum {
        exists = (sizeof(Test(MakeFrom())) == sizeof(Convertible)),
        same = false
    };
};


template<typename T> 
class Conversion<T, T>
{
public:
    enum {
        exists = true,
        same = true
    };
};


}//namespace 

#endif
